#pragma once

#include <iostream>
#include <string>
#include <etcd/Client.hpp>
#include <etcd/KeepAlive.hpp>
#include <etcd/Response.hpp>
#include <etcd/Value.hpp>
#include <etcd/Watcher.hpp>
#include <thread>
#include <memory>
#include <functional>
#include "./../../../common/log.hpp"


// 服务注册客户端类
class Registry
{
public:
    using ptr = std::shared_ptr<Registry>;

    Registry(const std::string& host)
        : _client(new etcd::Client(host))
        , _keep_alive(_client->leasekeepalive(3).get())
        , _lease_id(_keep_alive->Lease())
    {}

    ~Registry()
    {
        _keep_alive->Cancel();
    }

    bool registry(const std::string& key, const std::string val)
    {
        auto resp = _client->put(key, val, _lease_id).get();
        if(resp.is_ok() == 0)
        {
            ERROR_LOG("注册失败 {}",resp.error_message());
            return false;
        }
        else
        {
            TRACE_LOG("注册成功");
            return true;
        }
    }

private:
    std::shared_ptr<etcd::Client> _client;
    std::shared_ptr<etcd::KeepAlive> _keep_alive;
    uint64_t _lease_id;
};


// 服务发现客户端类

class Discovery
{
public:
    using ptr = std::shared_ptr<Discovery>;
    using CallbackFunc = std::function<void(std::string, std::string)>;

    Discovery(const std::string& host, const std::string& basedir, const CallbackFunc& put_cb, const CallbackFunc& del_cb)
        : _client(new etcd::Client(host))
        , _put_cb(put_cb)
        , _del_cb(del_cb)
    {
        // 先进行服务发现 就算获取basedir里面的数据
        auto resp = _client->ls(basedir).get();
        if(resp.is_ok() == 0)
        {
            ERROR_LOG("获取失败 {}",resp.error_message());
        }
        else
        {
            TRACE_LOG("获取成功");
        }
        int sz = resp.keys().size();
        for(int i = 0; i < sz; ++i)
        {
            if(_put_cb)
                _put_cb(resp.key(i), resp.value(i).as_string());
        }
        // 然后进行事件监控
        _watcher = std::make_shared<etcd::Watcher>(*_client, basedir, std::bind(&Discovery::callback, this, std::placeholders::_1), true);

    } 

private:
    void callback(const etcd::Response& resp)
    {
        if(resp.is_ok() == 0)
        {
            ERROR_LOG("事件错误 {}",resp.error_message());
            return;
        }
        for(const auto& ev : resp.events())
        {
            if(ev.event_type() == etcd::Event::EventType::PUT)
            {
                if(_put_cb)
                    _put_cb(ev.kv().key(), ev.kv().as_string());
                DEBUG_LOG("新增服务: {}-{}", ev.kv().key(), ev.kv().as_string());

            }
            else if(ev.event_type() == etcd::Event::EventType::DELETE_)
            {
                if(_del_cb)
                    _del_cb(ev.prev_kv().key(), ev.prev_kv().as_string());
                DEBUG_LOG("下线服务: {}-{}", ev.kv().key(), ev.kv().as_string());
                
            }
        }
    }
private:
    std::shared_ptr<etcd::Client> _client;
    std::shared_ptr<etcd::Watcher> _watcher;
    CallbackFunc _put_cb;
    CallbackFunc _del_cb;
};